package com.aynu.gulimall.auth.web;

import com.alibaba.fastjson.TypeReference;
import com.aynu.common.constant.AuthServerContant;
import com.aynu.common.exception.BizCodeEnume;
import com.aynu.common.utils.R;
import com.aynu.gulimall.auth.feign.MemberFeignService;
import com.aynu.gulimall.auth.feign.ThirdPartyFeignService;
import com.aynu.common.vo.MemberRespVo;
import com.aynu.gulimall.auth.vo.UserLoginVo;
import com.aynu.gulimall.auth.vo.UserRegisterVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mj
 * @version 1.0
 * @date 2021/3/14 22:57
 */
@Controller
@Slf4j
public class LoginController {

    @Autowired
    private ThirdPartyFeignService thirdPartyFeignService;
    
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MemberFeignService memberFeignService;

    @GetMapping({"login.html"})
    public String login(HttpSession session){
        Object attribute = session.getAttribute(AuthServerContant.LOGIN_USER_KEY);
        if (attribute==null){
            return "login";
        }else {
            return "redirect:http://gulimall.com";
        }
    }

    @GetMapping("sms/sendCode")
    @ResponseBody
    public R sendCode(@RequestParam("phone") String phone){

        //TODO 接口防刷

        String redisCode = redisTemplate.opsForValue().get(AuthServerContant.SMS_CODE_CACHE_PREFIX+phone);
        if (!StringUtils.isEmpty(redisCode)) {
            long redisCodeTime = Long.parseLong(redisCode.split("-")[1]);
            if (System.currentTimeMillis() - redisCodeTime < 60000){
                //在60秒内，不能再次发送验证码
                return R.error(BizCodeEnume.SMS_CODE_EXCEPTION.getCode(),BizCodeEnume.SMS_CODE_EXCEPTION.getMessage());
            }
        }
        //生成验证码
        String code = UUID.randomUUID().toString().substring(0,6)+"-"+System.currentTimeMillis();

        //存入redis临时保存，注册的时候需要验证，key：sms:code:手机号，value：code
        redisTemplate.opsForValue().set(AuthServerContant.SMS_CODE_CACHE_PREFIX+phone,code,60, TimeUnit.HOURS);

        log.info("给手机号：{}用户发送验证码:{}",phone,code);
        thirdPartyFeignService.sendCode(phone,code.split("-")[0]);

        return R.ok();
    }

    /**
     * TODO 分布式重定向携带数据
     * RedirectAttributes:重定向也能携带数据
     * 原理：利用session原理，将数据放在session中，只要跳到下一个页面取出数据以后，session里面的数据就会删除掉
     * TODO 需要解决分布式session问题
     * @param vo
     * @param result
     * @param attributes
     * @return
     */
    @PostMapping("/register")
    public String register(@Valid UserRegisterVo vo, BindingResult result, RedirectAttributes attributes){
        if (result.hasErrors()){
            //校检出错，转发到注册页
            Map<String, String> errors = result.getFieldErrors().stream().collect(
                    Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));

            attributes.addFlashAttribute("errors",errors);

            return "redirect:http://auth.gulimall.com/register.html";
        }
        //Request method 'POST' not supported
        //用户注册->/register【post】--转发/reg.html(路径映射默认都是get请求)

        //校验验证码
        String code = redisTemplate.opsForValue().get(AuthServerContant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
        //判断验证码是否为空
        if (!StringUtils.isEmpty(code)){
            if (code.split("-")[0].equals(vo.getCode())){
                //删除验证码;令牌机制
                redisTemplate.delete(AuthServerContant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
                log.info("调用远程服务，进行注册");
                R register = memberFeignService.register(vo);
                //如果远程调用成功
                if (register.getCode()==0){
                    //注册成功，返回登陆
                    return "redirect:http://auth.gulimall.com/login.html";
                }else {
                    //注册失败，携带失败原因返回注册页
                    Map<String, String> errors = new HashMap<>();
                    errors.put("msg",register.getMsg());
                    attributes.addFlashAttribute("errors",errors);
                    return "redirect:http://auth.gulimall.com/register.html";
                }
            }else {
                Map<String, String> errors = new HashMap<>();
                errors.put("code","验证码错误");
                attributes.addFlashAttribute("errors",errors);

                return "redirect:http://auth.gulimall.com/register.html";
            }
        }else {
            //注册失败，携带失败原因返回注册页
            Map<String, String> errors = new HashMap<>();
            errors.put("code","验证码错误");
            attributes.addFlashAttribute("errors",errors);
            return "redirect:http://auth.gulimall.com/register.html";
        }
    }

    @PostMapping("/login")
    public String login(UserLoginVo vo, RedirectAttributes attributes, HttpSession session){
        log.info("远程调用会员服务");
        R login = memberFeignService.login(vo);
        if (login.getCode()==0){
            //TODO 默认发的令牌。session=、作用域：当前域（解决session共享问题）
            //TODo 使用JSON的序列化来序列化对象数据到redis中
            session.setAttribute(AuthServerContant.LOGIN_USER_KEY,login.getData(new TypeReference<MemberRespVo>(){}));
            return "redirect:http://gulimall.com";
        }else {
            //注册失败，携带失败原因返回注册页
            Map<String, String> errors = new HashMap<>();
            errors.put("msg",login.getData("msg",new TypeReference<String>(){}));
            attributes.addFlashAttribute("errors",errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }
}
